// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.popman;

import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import zombie.characters.IsoZombie;
import zombie.characters.NetworkZombieVariables;
import zombie.core.network.ByteBufferWriter;
import zombie.core.raknet.UdpConnection;
import zombie.core.utils.UpdateLimit;
import zombie.debug.DebugLog;
import zombie.iso.IsoGridSquare;
import zombie.iso.IsoWorld;
import zombie.network.GameServer;
import zombie.network.MPStatistics;
import zombie.network.PacketTypes;
import zombie.network.ServerMap;
import zombie.network.packets.ZombiePacket;

public class NetworkZombiePacker {
    private static final NetworkZombiePacker instance = new NetworkZombiePacker();
    private final ArrayList<NetworkZombiePacker.DeletedZombie> zombiesDeleted = new ArrayList();
    private final ArrayList<NetworkZombiePacker.DeletedZombie> zombiesDeletedForSending = new ArrayList();
    private final HashSet<IsoZombie> zombiesReceived = new HashSet();
    private final ArrayList<IsoZombie> zombiesProcessing = new ArrayList();
    private final NetworkZombieList zombiesRequest = new NetworkZombieList();
    private final ZombiePacket packet = new ZombiePacket();
    private HashSet<UdpConnection> extraUpdate = new HashSet();
    private final ByteBuffer bb = ByteBuffer.allocate(1000000);
    UpdateLimit ZombieSimulationReliableLimit = new UpdateLimit(5000L);

    public static NetworkZombiePacker getInstance() {
        return instance;
    }

    public void setExtraUpdate() {
        for (int _int = 0; _int < GameServer.udpEngine.connections.size(); _int++) {
            UdpConnection udpConnection = (UdpConnection)GameServer.udpEngine.connections.get(_int);
            if (udpConnection.isFullyConnected()) {
                this.extraUpdate.add(udpConnection);
            }
        }
    }

    public void deleteZombie(IsoZombie z) {
        synchronized (this.zombiesDeleted) {
            this.zombiesDeleted.add(new NetworkZombiePacker.DeletedZombie(z.OnlineID, z.x, z.y));
        }
    }

    public void receivePacket(ByteBuffer _bb, UdpConnection connection) {
        short short0 = _bb.getShort();

        for (int int0 = 0; int0 < short0; int0++) {
            short short1 = _bb.getShort();
            IsoZombie isoZombie0 = ServerMap.instance.ZombieMap.get(short1);
            if (isoZombie0 != null && (connection.accessLevel == 32 || isoZombie0.authOwner == connection)) {
                this.deleteZombie(isoZombie0);
                DebugLog.Multiplayer.noise("Zombie was deleted id=%d (%f, %f)", isoZombie0.OnlineID, isoZombie0.x, isoZombie0.y);
                zombie.VirtualZombieManager.instance.removeZombieFromWorld(isoZombie0);
                MPStatistics.serverZombieCulled();
            }
        }

        short short2 = _bb.getShort();

        for (int int1 = 0; int1 < short2; int1++) {
            short short3 = _bb.getShort();
            IsoZombie isoZombie1 = ServerMap.instance.ZombieMap.get((short)short3);
            if (isoZombie1 != null) {
                this.zombiesRequest.getNetworkZombie(connection).zombies.add(isoZombie1);
            }
        }

        short short4 = _bb.getShort();

        for (int int2 = 0; int2 < short4; int2++) {
            this.parseZombie(_bb, connection);
        }
    }

    public void parseZombie(ByteBuffer _bb, UdpConnection connection) {
        this.packet.parse(_bb, connection);
        if (this.packet.id == -1) {
            DebugLog.General.error("NetworkZombiePacker.parseZombie id=" + this.packet.id);
        } else {
            try {
                IsoZombie isoZombie = ServerMap.instance.ZombieMap.get(this.packet.id);
                if (isoZombie == null) {
                    return;
                }

                if (isoZombie.authOwner != connection) {
                    NetworkZombieManager.getInstance().recheck(connection);
                    this.extraUpdate.add(connection);
                    return;
                }

                this.applyZombie(isoZombie);
                isoZombie.lastRemoteUpdate = 0;
                if (!IsoWorld.instance.CurrentCell.getZombieList().contains(isoZombie)) {
                    IsoWorld.instance.CurrentCell.getZombieList().add(isoZombie);
                }

                if (!IsoWorld.instance.CurrentCell.getObjectList().contains(isoZombie)) {
                    IsoWorld.instance.CurrentCell.getObjectList().add(isoZombie);
                }

                isoZombie.zombiePacket.copy(this.packet);
                isoZombie.zombiePacketUpdated = true;
                synchronized (this.zombiesReceived) {
                    this.zombiesReceived.add(isoZombie);
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }

    public void postupdate() {
        this.updateAuth();
        synchronized (this.zombiesReceived) {
            this.zombiesProcessing.clear();
            this.zombiesProcessing.addAll(this.zombiesReceived);
            this.zombiesReceived.clear();
        }

        synchronized (this.zombiesDeleted) {
            this.zombiesDeletedForSending.clear();
            this.zombiesDeletedForSending.addAll(this.zombiesDeleted);
            this.zombiesDeleted.clear();
        }

        for (UdpConnection udpConnection : GameServer.udpEngine.connections) {
            if (udpConnection != null && udpConnection.isFullyConnected()) {
                this.send(udpConnection);
            }
        }
    }

    private void updateAuth() {
        ArrayList arrayList = IsoWorld.instance.CurrentCell.getZombieList();

        for (int _int = 0; _int < arrayList.size(); _int++) {
            IsoZombie isoZombie = (IsoZombie)arrayList.get(_int);
            NetworkZombieManager.getInstance().updateAuth(isoZombie);
        }
    }

    public int getZombieData(UdpConnection connection, ByteBuffer _bb) {
        int int0 = _bb.position();
        _bb.putShort((short)300);
        int int1 = 0;

        try {
            NetworkZombieList.NetworkZombie networkZombie = this.zombiesRequest.getNetworkZombie(connection);

            while (!networkZombie.zombies.isEmpty()) {
                IsoZombie isoZombie0 = (IsoZombie)networkZombie.zombies.poll();
                isoZombie0.zombiePacket.set(isoZombie0);
                if (isoZombie0.OnlineID != -1) {
                    isoZombie0.zombiePacket.write(_bb);
                    isoZombie0.zombiePacketUpdated = false;
                    if (++int1 >= 300) {
                        break;
                    }
                }
            }

            for (int int2 = 0; int2 < this.zombiesProcessing.size(); int2++) {
                IsoZombie isoZombie1 = (IsoZombie)this.zombiesProcessing.get(int2);
                if (isoZombie1.authOwner != null
                    && isoZombie1.authOwner != connection
                    && connection.RelevantTo(isoZombie1.x, isoZombie1.y, (float)((connection.ReleventRange - 2) * 10))
                    && isoZombie1.OnlineID != -1) {
                    isoZombie1.zombiePacket.write(_bb);
                    isoZombie1.zombiePacketUpdated = false;
                    int1++;
                }
            }

            int int3 = _bb.position();
            _bb.position(int0);
            _bb.putShort((short)int1);
            _bb.position(int3);
        } catch (BufferOverflowException bufferOverflowException) {
            bufferOverflowException.printStackTrace();
        }

        return int1;
    }

    public void send(UdpConnection connection) {
        this.bb.clear();
        this.bb.put((byte)(connection.isNeighborPlayer ? 1 : 0));
        int int0 = this.bb.position();
        short _short = 0;
        this.bb.putShort((short)0);

        for (NetworkZombiePacker.DeletedZombie deletedZombie : this.zombiesDeletedForSending) {
            if (connection.RelevantTo(deletedZombie.x, deletedZombie.y)) {
                _short++;
                this.bb.putShort(deletedZombie.OnlineID);
            }
        }

        int int1 = this.bb.position();
        this.bb.position(int0);
        this.bb.putShort(_short);
        this.bb.position(int1);
        NetworkZombieManager.getInstance().getZombieAuth(connection, this.bb);
        int int2 = this.getZombieData(connection, this.bb);
        if (int2 > 0 || connection.timerSendZombie.check() || this.extraUpdate.contains(connection)) {
            this.extraUpdate.remove(connection);
            connection.timerSendZombie.reset(3800L);
            ByteBufferWriter byteBufferWriter = connection.startPacket();
            PacketTypes.PacketType packetType;
            if (this.ZombieSimulationReliableLimit.Check()) {
                packetType = PacketTypes.PacketType.ZombieSimulationReliable;
            } else {
                packetType = PacketTypes.PacketType.ZombieSimulation;
            }

            packetType.doPacket(byteBufferWriter);
            byteBufferWriter.bb.put(this.bb.array(), 0, this.bb.position());
            packetType.send(connection);
        }
    }

    private void applyZombie(IsoZombie isoZombie) {
        IsoGridSquare isoGridSquare = IsoWorld.instance.CurrentCell.getGridSquare((int)this.packet.x, (int)this.packet.y, this.packet.z);
        isoZombie.lx = isoZombie.nx = isoZombie.x = this.packet.realX;
        isoZombie.ly = isoZombie.ny = isoZombie.y = this.packet.realY;
        isoZombie.lz = isoZombie.z = (float)this.packet.realZ;
        isoZombie.setForwardDirection(isoZombie.dir.ToVector());
        isoZombie.setCurrent(isoGridSquare);
        isoZombie.networkAI.targetX = this.packet.x;
        isoZombie.networkAI.targetY = this.packet.y;
        isoZombie.networkAI.targetZ = this.packet.z;
        isoZombie.networkAI.predictionType = this.packet.moveType;
        NetworkZombieVariables.setInt(isoZombie, (short)0, this.packet.realHealth);
        NetworkZombieVariables.setInt(isoZombie, (short)2, this.packet.speedMod);
        NetworkZombieVariables.setInt(isoZombie, (short)1, this.packet.target);
        NetworkZombieVariables.setInt(isoZombie, (short)3, this.packet.timeSinceSeenFlesh);
        NetworkZombieVariables.setInt(isoZombie, (short)4, this.packet.smParamTargetAngle);
        NetworkZombieVariables.setBooleanVariables(isoZombie, this.packet.booleanVariables);
        isoZombie.setWalkType(this.packet.walkType.toString());
        isoZombie.realState = this.packet.realState;
    }

    class DeletedZombie {
        short OnlineID;
        float x;
        float y;

        public DeletedZombie(short _short, float float0, float float1) {
            this.OnlineID = _short;
            this.x = float0;
            this.y = float1;
        }
    }
}
